package chapter05;

import org.junit.Test;

import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.IntStream;

/**
 * @author chisheng
 * @since 2021-11-11
 */
public class BooleanLockTest {

    /**
     * 定义一个 BooleanLock
     */
    private final Lock lock = new BooleanLock();

    public void syncMethod() {
        try {
            // 加锁
            lock.lock();
            int randomInt = new Random().nextInt(10);
            System.out.printf("%s get the lock and will hold it for %d seconds.%n", Thread.currentThread().getName(), randomInt);
            TimeUnit.SECONDS.sleep(randomInt);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 释放锁
            lock.unlock();
        }
    }

    public void syncMethodTimeout() {
        try {
            // 1000ms 内未获得锁将会抛出超时异常
            lock.lock(1000);
            int randomInt = new Random().nextInt(10);
            System.out.printf("%s get the lock and will hold it for %d seconds.%n", Thread.currentThread().getName(), randomInt);
            TimeUnit.SECONDS.sleep(randomInt);
        } catch (InterruptedException | TimeoutException e) {
            e.printStackTrace();
        } finally {
            // 释放锁
            lock.unlock();
        }
    }

    @Test
    public void testSynchronized() throws InterruptedException {
        BooleanLockTest blt = new BooleanLockTest();
        IntStream.range(0, 10).mapToObj(i -> new Thread(blt::syncMethod)).forEach(Thread::start);

        // 避免主线程关闭
        TimeUnit.SECONDS.sleep(100);
    }

    @Test
    public void testInterrupted() throws InterruptedException {
        BooleanLockTest blt = new BooleanLockTest();
        new Thread(blt::syncMethod, "T1").start();
        TimeUnit.SECONDS.sleep(1);
        Thread t2 = new Thread(blt::syncMethod, "T2");
        t2.start();
        TimeUnit.SECONDS.sleep(2);
        t2.interrupt();
    }

    @Test
    public void testTimeout() throws InterruptedException {
        BooleanLockTest blt = new BooleanLockTest();
        IntStream.range(0, 10).mapToObj(i -> new Thread(blt::syncMethodTimeout)).forEach(Thread::start);

        // 避免主线程关闭
        TimeUnit.SECONDS.sleep(100);
    }

}
